// Package wechat contains platform certificate store utilities for signature verification.
package wechat

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"fmt"
	"sync"
	"time"

	"github.com/we-pay-kit/we-pay-kit/internal/logger"
)

// CertificateInfo holds certificate metadata
type CertificateInfo struct {
	Certificate  *x509.Certificate
	Serial       string
	ExpireTime   time.Time
	EffectiveTime time.Time
}

var (
	certMu   sync.RWMutex
	certBySn = map[string]*CertificateInfo{}
)

// SetPlatformCert registers a platform certificate by serial number (hex string).
func SetPlatformCert(serial string, pemData string) error {
	block, _ := pem.Decode([]byte(pemData))
	if block == nil {
		return fmt.Errorf("invalid PEM data")
	}
	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return fmt.Errorf("parse certificate: %w", err)
	}
	
	certInfo := &CertificateInfo{
		Certificate:   cert,
		Serial:        serial,
		ExpireTime:    cert.NotAfter,
		EffectiveTime: cert.NotBefore,
	}
	
	certMu.Lock()
	certBySn[serial] = certInfo
	certMu.Unlock()
	
	logger.Get().Info(fmt.Sprintf("Platform certificate registered: serial=%s, expire=%s", serial, cert.NotAfter.Format(time.RFC3339)))
	return nil
}

// GetPlatformCert returns the platform certificate by serial number.
func GetPlatformCert(serial string) *x509.Certificate {
	certMu.RLock()
	certInfo := certBySn[serial]
	certMu.RUnlock()
	
	if certInfo == nil {
		return nil
	}
	
	// Check if certificate is still valid
	now := time.Now()
	if now.After(certInfo.ExpireTime) || now.Before(certInfo.EffectiveTime) {
		logger.Get().Warn(fmt.Sprintf("Certificate expired or not yet effective: serial=%s", serial))
		return nil
	}
	
	return certInfo.Certificate
}

// ListCertificates returns all registered certificates
func ListCertificates() map[string]*CertificateInfo {
	certMu.RLock()
	defer certMu.RUnlock()
	
	result := make(map[string]*CertificateInfo)
	for k, v := range certBySn {
		result[k] = v
	}
	return result
}

// RemoveExpiredCertificates removes expired certificates from store
func RemoveExpiredCertificates() int {
	certMu.Lock()
	defer certMu.Unlock()
	
	now := time.Now()
	expiredCount := 0
	
	for serial, certInfo := range certBySn {
		if now.After(certInfo.ExpireTime) {
			delete(certBySn, serial)
			expiredCount++
			logger.Get().Info(fmt.Sprintf("Removed expired certificate: serial=%s", serial))
		}
	}
	
	return expiredCount
}

// DecryptAESGCM decrypts WeChat Pay v3 encrypted data using AES-256-GCM
func DecryptAESGCM(apiV3Key, associatedData, nonce, ciphertext string) ([]byte, error) {
	key := []byte(apiV3Key)
	if len(key) != 32 {
		return nil, fmt.Errorf("API v3 key must be 32 bytes")
	}
	
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, fmt.Errorf("create cipher: %w", err)
	}
	
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, fmt.Errorf("create GCM: %w", err)
	}
	
	nonceBytes := []byte(nonce)
	ciphertextBytes, err := base64.StdEncoding.DecodeString(ciphertext)
	if err != nil {
		return nil, fmt.Errorf("decode ciphertext: %w", err)
	}
	
	plaintext, err := gcm.Open(nil, nonceBytes, ciphertextBytes, []byte(associatedData))
	if err != nil {
		return nil, fmt.Errorf("decrypt: %w", err)
	}
	
	return plaintext, nil
}
